"ZX80 BRAIN" & "ZX81 BRAIN" RPN CALCULATORS
===========================================

written by J.R. Waterman, 1 - 14 March 2017


BACKGROUND
==========

There are times when I get the urge to remind myself "I was good at something once".
Chemistry, for instance - when I first enthusiastically joined the World Of Spectrum
forums, I was a PhD student, and even though I finally made it across the finish line
there in 2006, there were times where I really thought I wasn't up to it. There were other
diverting activities that reminded me I was good at something, and Spectrum programming
was one of those - that's what brought me to submit several (intentionally bad) entries to
the CCSCGC in 2004... one of which was written in early 1989 when I was nine, but I found
it on an old tape I'd kept and didn't want to waste it.

I've found myself in much the same frame of mind recently, and set myself a small
challenge. Of the many Ian Taylors in this world, one of them was my physics teacher at
Bishop's Stortford College from 1993-97, who taught me most of GCSE and throughout A-level
as well as some rudimentary computer science in 1992-93. He was something of an Apple
devotee - it was probably his decision that the school used Mac Plus, Classic and LC II
models - as well as Hewlett-Packard RPN scientific calculators. He showed us how RPN
worked and how it was different to the Casio and Sharp models we all had, and also showed
us an RPN calculator program he'd written on an Apple IIe (with a green monitor to hammer
home how old it was).

I could have done the same in my first enthusiastic of Spectrum rediscovery here alongside
the CCSCGC programs, but for whatever reason, it took until 2017 for me to get the idea
that if my physics teacher of 20 years ago could write an RPN calculator program, why
couldn't I? Why had I never tried to do it before?

So I did.


RPN CALCULATORS FOR BEGINNERS
=============================

I am doing this authentically. Hewlett-Packard may be the name most inextricably linked
with RPN calculators, but the Sinclair Scientific (from 1974) used RPN.
https://en.wikipedia.org/wiki/Sinclair_Scientific

Essentially, Reverse Polish Notation means you enter calculations a different way to the
vast majority of models most people are familiar with. Numbers are entered into a stack
with the ENTER key, and pressing a function key will perform that function on the bottom
two numbers in the stack. For example:

The sequence: 4, ENTER, 3, ENTER, 2, +, +
- this adds 2 + 3, then the resultant 5 is added to 4. Answer: 9.

The sequence: 4, ENTER, 3, ENTER, 2, +, -
- this adds 2 + 3, then the resultant 5 is subtracted from 4. Answer: -1.

The sequence: 4, ENTER, 3, ENTER, 2, -, +
- this subtracts 2 from 3, then the resultant 1 is added to 4. Answer: 5.

The sequence: 4, ENTER, 3, ENTER, 2, ×, ÷
- this multiplies 2 by 3, then divides 4 by the resultant 6. Answer: 0.666667.

For a detailed explanation of Reverse Polish Notation, consult the All-Knowing Oracle:
https://en.wikipedia.org/wiki/Reverse_Polish_notation


"ZX80 BRAIN" RPN CALCULATOR - FEATURES AND EXPLANATION
======================================================

I'd already written a screen-drawing routine for the "ZX81 Brain" version when I realised,
it was a bit ambitious to make a calculator with all the scientific functions I could fit
on it, until I'd tested the routines I'd need to set up on a simpler four-function version
which I've called the "ZX80 Brain". So that's all you get - ten digits, a decimal point,
add, subtract, multiply, divide, clear and the ENTER key that screams "this is an RPN
calculator" - for a total of 17 working keys, arranged in a 4 × 5 pattern with three
blanks as on a base-model 1984 Vauxhall Cavalier which will leave you wondering what
you're missing out on.

(Aside: the names of the "brains" were the bottom two skill levels of Starfire, the early
and mostly BASIC-based release from Virgin Games that Codemasters would have called "Super
Star Trek Simulator", which is obvious when the game draws the ship's top and side views.)

To keep the authentic Sinclair-ness of this calculator program, I've mapped the function
keys to those it would correspond to on a Spectrum, usually with SYMBOL SHIFT. The program
uses POKE 23658,8 to force CAPS LOCK on so only one code (that of a capital letter) has to
be checked for. If you're using this program on an original rubber-keyed Spectrum (hence
only the tape or microdrive version!) then this will present no problem, but if you're on
a Spectrum + or higher, bear in mind that the . key will not work to produce a decimal
point - you have to use the M key! Neither will pressing SYMBOL SHIFT with the appropriate
letter work - just the letter key will operate the function.

I'm quite pleased that I've made some routines work in BASIC that I could never have 
worked out when I was much younger, but I'm far more likely to think of 30 years later:

- Loaded in the ZX80 character set (which I'd saved ages ago and I have a program to make
  defining character sets really easy).
- The number keys are all centralised into 2 × 2 squares by PRINTing them where I've put
  the stack with INK and PAPER the same, then reading the 6 × 7 areas with the POINT
  function and PLOTting them in the right place. If they'd only had to be centralised
  between two rows I could have used POKE 23606 to shift them vertically, but I needed to
  do it horizontally as well.
- Shown a "key press on the screen" by temporarily turning on the BRIGHT channel for that
  2 × 2 square and turning it off again when the process was done, with a POKE of the
  display file where the attributes are held. It may seem excessive to define an array -
  DIM z(90) - with 90 values, most of which are unused, but I'd read the key press with
  LET i=CODE INKEY$, then z(i) would hold the address that needed to be POKEd (up or down
  by 64) for the top-left of the 2 × 2 square that I'd defined for that key on screen.
  It's four POKEs in total (value, +1, +32, +33).

I am not an advanced programmer by any means, I know nothing about machine code, and I'm
never going to be in the league of Jonathan Cauldwell, Bob Smith, Einar Saukas and others
even if I start learning now and never stop until I'm well into my 60s (assuming I live
that long). But seeing as this is my level, shown here, imagine my delight when I managed
to get those last two routines above to work without consulting anyone on this forum first
who would be able to do it in five seconds. That's the crucial point.

Other things I managed to check for, given that the number at the bottom of the stack has
to be held in a string and that makes it harder, is:

- only keys shown on screen will actually do anything;
- you're not trying to divide by zero;
- the stack won't fill beyond 17 values or empty beyond a zero stored at the bottom;
- the decimal point can't be entered twice;
- there's no exponential key (in this version) but it checks to see if there is one in the
  working value anyway, when a calculation results in a number beyond 99,999,999;
- leading zeroes aren't entered.

It's slow, I know that - because I've written it in +3 BASIC which goes mad if I try to
use redefined character sets on the BASIC editor, I've had to POKE 23607,249 every time I
want to PRINT something on the stack, and POKE 23607,60 at the end of the subroutine every
time. Hence I thought the "ZX80 Brain" was an appropriate name.

I know what you're all thinking: "...but the ZX80 couldn't handle decimals!" Well... like
a "ZX80-and-a-half", if you like, it can handle decimals, but doesn't always get it right
when checking that there is one. I've set two variables as flags - d and e, set to either
0 or 1. d = 1 if there's a decimal point in the value at the bottom of the stack, e = 1 if
there's an E+ or E- value in there; if one appears as the result of a calculation, d and e
are both automatically set to 1. I've set d to 1 if the M key (for .) is pressed, and both
d and e back to 0 once the ENTER key is pressed and that number is moved up the stack.
I've used the variable o to hold the result of a calculation before the stack is moved,
and I've checked:
- IF o=INT o THEN LET d=0
- IF o<>INT o THEN LET d=1 (both lines are in just to make sure)
- IF o>=1e8 THEN LET d=1: LET e=1 (because such a number will be held in scientific
  notation, and even if it's one digit with no decimal point such as 1E+8, the decimal
  point key needs to be disabled anyway until this number is put into the stack).

Whatever I do, I find the decimal point flag gets stuck on and it beeps at me as if
there's a decimal point there, even when there isn't. Sometimes it's because the display
is holding a non-integer value but it can't display the decimal point because there are
too many digits, other times it's a mystery.


"ZX81 BRAIN" RPN CALCULATOR - FEATURES AND EXPLANATION
======================================================

First there was the "ZX80 Brain" four-function RPN calculator, now meet its expanded
brother, the "ZX81 Brain" RPN calculator with scientific functions.

The screen for the "ZX81 Brain" calculator was designed first, with 30 keys in a 6 × 5
array - the space for the top two rows in the "ZX80 Brain" version was instead filled with
the ZX80 logo. I hadn't decided what extra scientific functions should be added on the top
two rows when I switched to the "ZX80 Brain" version, so it gave me time to work out the
best permutation of such functions.

For the "ZX81 Brain" version I could have used the standard character set, but I thought
I'd make it a bit more like the early Sinclair calculators and redefine 0-9, E, + and -
to make it look like a seven-segment LED display in the stack. This has meant I have had
to keep all the constant swapping between the redefined character set (POKE 23607,249) and
the standard character set (POKE 23607,60) to ensure the screen doesn't fill with junk in
128/+3 BASIC. (It's annoying, because I'd have liked to see the listing for the "ZX80
Brain" calculator in the authentic ZX80 font!)

The extra features the "ZX81 Brain" calculator adds over the "ZX80 Brain" are:

- a fifth "regular" function, the power key;
  = mapped to "H", where the ^ symbol is
- the plus/minus key and the ABS function to convert any value to always positive
  (which was really a result of me having one key spare and not wanting to waste it...);
  = plus/minus is mapped to "N" for "negative", as the Spectrum has no plus/minus
  = ABS is mapped to "G" where this function is on the Spectrum
  = a routine will disable trying to negate zero; ABS has no effect on zero
- trigonometric functions SIN, COS, TAN;
  = mapped to "Q", "W" and "E" where these functions are on the Spectrum
  = the routine can check for values where TAN has an asymptote, but though it is
    correctly coded it won't always work (see "known problems" below)
- logarithmic functions, ln and log10;
  = ln mapped to "Z" where the Spectrum's LN function is
  = log10 uses "A" as it is a free key next to "Z".
  = a routine disables taking logarithms of zero or negative numbers
- pi key
  = mapped to "P", as "M" where PI is on a Spectrum has been used for the decimal point
- reciprocal key;
  = mapped to "R"
  = a routine will disable taking the reciprocal of zero
- square root key;
  = mapped to "S", as "H" (where the SQR function is) is used for the power key
  = a routine will disable square roots of negative numbers
  = this is a short cut, other roots are available by calculating powers of reciprocals
    e.g. cube root of x = x^(1/3)
- an exponential key allows values up to 10^38 to be entered (beyond which the
  program will stop with "6 Number too big" - see "known problems" below);
  = mapped to "X"; even though the key produces "E+" in the current entry, the "E" key is
    used for TAN and although EXP on a Spectrum keyboard refers to e^x, it's handy having
    that printed there. EXP on a Casio scientific calculator does exactly the same as the
    EXP on this screen after all!
- an inverse function key, which inverts five functions and extends the exponent
  = mapped to "I", as "M" where the INVERSE function is on a Spectrum has been used for
    the decimal point
  = press it and the BRIGHT channel stays on until the next key press
  = logarithm functions are inverted; ln becomes e^x, log10 becomes 10^x
  = trigonometric functions are inverted; SIN, COS, TAN become ASN, ACS, ATN respectively
  = a routine disables calculating ASN and ACS for values greater than +1 or less than -1
  = using the INV key before the EXP key produces "E-" on the current entry instead of
    "E+" and allows entry of reciprocal scientific notation
  = the key is always reset after the second key press; it will have no effect on any keys
    other than these six
- a redesigned screen to reflect the black, red and white of the ZX81;
- the aforementioned seven-segment character set, in bright red to look like glowing LEDs.

In a horrible twist of irony, the extra features added to the "ZX81 Brain" calculator -
which mean many more key presses to check for in each program cycle - have slowed it down
to the point where it really struggles with a full stack, particularly when executing a
single-value function - there are more of these and five have inverses, which means there
are a lot of lines of code to execute every time one is used! So the "ZX80 Brain"
calculator is faster for the basics, the "ZX81 Brain" calculator can do more. (Of course,
you could just use the Spectrum's functions in BASIC, I've just made them look flash with
all my screen POKEs!)

Features I haven't managed to get on this calculator (and would never have been likely to
anyway) are:

- non-decimal number bases (binary and hexadecimal at least) and the ability to convert
  between them;
- complex numbers;
- logical operators NOT, AND, OR and XOR; 
- angle measurements other than radians (degrees, mils, grads... whatever they are!);
- degree-minute-second notation;
- fractions;
- hyperbolic functions (though these can be calculated with exponential identities);
- derived trigonometric functions (SEC, CSC, COT - though these can also be calculated
  with reciprocals of COS, SIN and TAN respectively, and has anyone ever seen these on a
  scientific calculator, let alone an 8-bit micro?)
- average and standard deviation calculated from all the values entered into the stack.


LOADING FROM ANY FORMAT
=======================

Tape version:		LOAD "zx80calc"			LOAD "zx81calc"
+3 Disc version:	LOAD "zx80calc.bas"		LOAD "zx81calc.bas"
Microdrive version:	LOAD *"m";1;"zx80calc"	LOAD *"m";1;"zx81calc"

Note that the microdrive version is automatically set to load the character sets from
microdrive #1 - only use this drive if you have more than one connected.

Other files:
zx80chrs (tape/microdrive) / zx80chrs.bin (+3 disc) - LOAD [filename] CODE 64000,768
	- full ZX80 character set, with both sets of letters defined as upper case and
	  Spectrum-only characters left intact.
digichrs (tape/microdrive) / digichrs.bin (+3 disc) - LOAD [filename] CODE 64000,768
	- seven-segment digital numbers, +, -, E for use with the ZX81 Brain calculator;
	  the + is a bit cheaty, mind, it needed an extra segment...
zx80scrn (tape/microdrive) / zx80scrn.bin (+3 disc) - LOAD [filename] SCREEN$
	- screenshot for the ZX80 Brain calculator
zx81scrn (tape/microdrive) / zx81scrn.bin (+3 disc) - LOAD [filename] SCREEN$
	- screenshot for the ZX81 Brain calculator

I wonder if there are any other formats I could have transferred this to...?


KNOWN PROBLEMS
==============

ZX80 BRAIN:
- doesn't always recognise when a number no longer has a decimal point, usually because
  there is a very small decimal in the string that the number display can't handle when it
  tries to print VAL of the string.
- no exponent key, but the calculator can handle numbers from 10^8 to (somewhere between
  10^38 and 10^39) as the result of a calculation. Any calculation that exceeds 10^38, or
  an attempt to press number keys that taked the exponent above 10^38, will crash the
  program with "6 Number too big". (This also happens with exponents below -38.)
  
ZX81 BRAIN - as above plus:
- exponent key added; so far there appears to be no easy way to prevent the exponent from
  exceeding 10^38 accidentally, or as the result of a calculation.
- PI is stored to 7 decimal places. Trig functions work OK except in certain cases where
  the value of the trig function should be 0 but the accuracy of the stored value of PI is
  not enough and the function returns the value 7.3145904E-10.
  = e.g.: if X = PI*0.5, COS X should be 0 but returns 7.3145904E-10; the same result
    occurs with COS of-PI*0.5. Strangely, using PI/2 returns the correct value 0. Higher
    values of X where COS X should equal 0 - i.e. PI*1.5, PI*2.5, etc - are fine whether
    using PI*1.5 or 3*PI/2. TAN of -PI does the same and TAN of multiples of -PI returns
    the same multiple of the inaccurate value - i.e. X = 2*PI, TAN X = 2*(7.1345904E-10).
  = annoyingly, this means the attempt to check for asymptotes in the TAN function fails
    for any value of X for which this program will return COS X = 7.1345904E-10; this is
    because it does not recognise the variable OT = ((s(1)+(PI/2))/PI as being
    an integer (because it's very slightly off, not even enough for the display to handle)
    and an attempt to evaluate TAN X returns a very large value that crashes the program
    with "6 Number too big". The routine does at least work in theory - divide PI by 2
    (don't multiply by 0.5!), COS returns 0, TAN will beep for an error.

  

